package xin.altitude.commons.collection4;

import org.apache.commons.collections4.Factory;
import org.apache.commons.collections4.IterableMap;
import org.apache.commons.collections4.IterableSortedMap;
import org.apache.commons.collections4.OrderedMap;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;

import java.io.PrintStream;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.SortedMap;
import java.util.function.Function;

/**
 * Provides utility methods and decorators for
 * {@link Map} and {@link SortedMap} instances.
 *
 * @author <a href="http://www.altitude.xin" target="_blank">Java知识图谱</a>
 * @author <a href="https://gitee.com/decsa/ucode-cms-vue" target="_blank">UCode CMS</a>
 * @author <a href="https://space.bilibili.com/1936685014" target="_blank">B站视频</a>
 **/
public class MapUtils {
    private MapUtils() {
    }
    
    /**
     * <p>将{@code Map}实例的{@code Key}和{@code Value}反转 生成新{@code Map}实例</p>
     * <p>如果K-V结构非一一对应，转换前相同Value值，在转换后取最后出现的Key，参考示例</p>
     * <pre>
     *     K        V                   K       V
     *     1        a                   a       2
     *     2        a                   b       3
     *     3        b
     * </pre>
     *
     * @param map {@code Map}实例
     * @param <K> {@code Key}的类型
     * @param <V> {@code Value}的类型
     * @return 新{@code Map}实例
     */
    public static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.invertMap(map);
    }
    
    /**
     * <p>从{@code Map}实例中通过<code>key</code>取出Value值
     * 防止因{@code Map}实例为<code>null</code>而产生运行时空指针异常</p>
     * <p>{@link org.apache.commons.collections4.MapUtils}工具类中所有<code>getXXX</code>方法均适用于本注释</p>
     * <p>在Java 8环境下 使用{@link java.util.Optional}能作为更好的替代</p>
     * <pre>
     *      Optional.ofNullable(map).map(e -&gt; e.get(key)).orElse(null)
     * </pre>
     *
     * @param map {@code Map}实例 允许为<code>null</code>
     */
    public static <K, V> V getObject(final Map<? super K, V> map, final K key) {
        return org.apache.commons.collections4.MapUtils.getObject(map, key);
    }
    
    
    /**
     * <p>从{@code Map}实例中通过<code>key</code>取出Value值
     * 防止因{@code Map}实例为<code>null</code>而产生运行时空指针异常</p>
     * <p>{@link org.apache.commons.collections4.MapUtils}工具类中所有<code>getXXX</code>方法均适用于本注释</p>
     * <p>在Java 8环境下 使用{@link java.util.Optional}能作为更好的替代</p>
     * <pre>
     *      Optional.ofNullable(map).map(e -&gt; e.get(key)).orElse(defaultValue)
     * </pre>
     *
     * @param map {@code Map}实例 允许为<code>null</code>
     */
    public static <K, V> V getObject(final Map<K, V> map, final K key, final V defaultValue) {
        return org.apache.commons.collections4.MapUtils.getObject(map, key, defaultValue);
    }
    
    
    public static <K, V> Properties toProperties(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.toProperties(map);
    }
    
    public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
        return org.apache.commons.collections4.MapUtils.toMap(resourceBundle);
    }
    
    public static void verbosePrint(final PrintStream out, final Object label, final Map<?, ?> map) {
        org.apache.commons.collections4.MapUtils.verbosePrint(out, label, map);
    }
    
    public static void debugPrint(final PrintStream out, final Object label, final Map<?, ?> map) {
        org.apache.commons.collections4.MapUtils.debugPrint(out, label, map);
    }
    
    public static <K, V> Map<K, V> putAll(final Map<K, V> map, final Object[] array) {
        return org.apache.commons.collections4.MapUtils.putAll(map, array);
    }
    
    public static <K, V> Map<K, V> emptyIfNull(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.emptyIfNull(map);
    }
    
    public static boolean isEmpty(final Map<?, ?> map) {
        return org.apache.commons.collections4.MapUtils.isEmpty(map);
    }
    
    public static boolean isNotEmpty(final Map<?, ?> map) {
        return org.apache.commons.collections4.MapUtils.isNotEmpty(map);
    }
    
    public static <K, V> Map<K, V> synchronizedMap(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.synchronizedMap(map);
    }
    
    public static <K, V> Map<K, V> unmodifiableMap(final Map<? extends K, ? extends V> map) {
        return org.apache.commons.collections4.MapUtils.unmodifiableMap(map);
    }
    
    /**
     * <p>按照断言器过滤{@code Map} 形成新的{@code Map}实例</p>
     * <p>断言器相应参数允许为<code>null</code>，意味着放弃通过该条件进行过滤</p>
     * <p>{@link java.util.Map}是{@link org.apache.commons.collections4.IterableMap}的父类
     * 若没有使用增强功能的需求，则可以直接使用{@link java.util.Map}接收返回值，减少方法理解难度</p>
     *
     * @param map       输入{@code Map}实例
     * @param keyPred   Key断言器 参数允许为<code>null</code>
     * @param valuePred Value断言器 <code>null</code>
     * @param <K>       {@code Map}Key的类型
     * @param <V>       {@code Map}Value的类型
     * @return 新{@code Map}实例
     */
    public static <K, V> IterableMap<K, V> predicatedMap(final Map<K, V> map, final Predicate<? super K> keyPred, final Predicate<? super V> valuePred) {
        return org.apache.commons.collections4.MapUtils.predicatedMap(map, keyPred, valuePred);
    }
    
    public static <K, V> IterableMap<K, V> transformedMap(final Map<K, V> map, final Transformer<? super K, ? extends K> keyTransformer, final Transformer<? super V, ? extends V> valueTransformer) {
        return org.apache.commons.collections4.MapUtils.transformedMap(map, keyTransformer, valueTransformer);
    }
    
    public static <K, V> IterableMap<K, V> fixedSizeMap(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.fixedSizeMap(map);
    }
    
    public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map, final Factory<? extends V> factory) {
        return org.apache.commons.collections4.MapUtils.lazyMap(map, factory);
    }
    
    public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map, final Transformer<? super K, ? extends V> transformerFactory) {
        return org.apache.commons.collections4.MapUtils.lazyMap(map, transformerFactory);
    }
    
    public static <K, V> OrderedMap<K, V> orderedMap(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.orderedMap(map);
    }
    
    public static <K, V> SortedMap<K, V> synchronizedSortedMap(final SortedMap<K, V> map) {
        return org.apache.commons.collections4.MapUtils.synchronizedSortedMap(map);
    }
    
    public static <K, V> SortedMap<K, V> unmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
        return org.apache.commons.collections4.MapUtils.unmodifiableSortedMap(map);
    }
    
    public static <K, V> SortedMap<K, V> predicatedSortedMap(final SortedMap<K, V> map, final Predicate<? super K> keyPred, final Predicate<? super V> valuePred) {
        return org.apache.commons.collections4.MapUtils.predicatedSortedMap(map, keyPred, valuePred);
    }
    
    public static <K, V> SortedMap<K, V> transformedSortedMap(final SortedMap<K, V> map, final Transformer<? super K, ? extends K> keyTransformer, final Transformer<? super V, ? extends V> valueTransformer) {
        return org.apache.commons.collections4.MapUtils.transformedSortedMap(map, keyTransformer, valueTransformer);
    }
    
    public static <K, V> SortedMap<K, V> fixedSizeSortedMap(final SortedMap<K, V> map) {
        return org.apache.commons.collections4.MapUtils.fixedSizeSortedMap(map);
    }
    
    public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map, final Factory<? extends V> factory) {
        return org.apache.commons.collections4.MapUtils.lazySortedMap(map, factory);
    }
    
    public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map, final Transformer<? super K, ? extends V> transformerFactory) {
        return org.apache.commons.collections4.MapUtils.lazySortedMap(map, transformerFactory);
    }
    
    /**
     * <p>将列表转化成{@code Map}</p>
     * <p>如果仅仅是有将列表转化成{@code Map}的需求 Java8环境下基于流有更好的实现
     * 参考{@link xin.altitude.cms.common.util.EntityUtils#toMap(Collection, Function)}</p>
     * <pre>
     *     StreamSupport.stream(elements.spliterator(),false)
     *     .collect(Collectors.toMap(keyAction, Function.identity()))
     * </pre>
     *
     * @param map
     * @param elements
     * @param keyTransformer
     * @param <K>
     * @param <V>
     */
    public static <K, V> void populateMap(final Map<K, V> map, final Iterable<? extends V> elements, final Transformer<V, K> keyTransformer) {
        org.apache.commons.collections4.MapUtils.populateMap(map, elements, keyTransformer);
    }
    
    
    /**
     * <p>将列表转化成{@code Map}</p>
     * <p>如果仅仅是有将列表转化成{@code Map}的需求 Java8环境下基于流有更好的实现
     * 参考{@link xin.altitude.cms.common.util.EntityUtils#toMap(Collection, Function, Function)}</p>
     * <pre>
     *     StreamSupport.stream(elements.spliterator(),false)
     *     .collect(Collectors.toMap(keyAction, valueAction))
     * </pre>
     *
     * @param map
     * @param elements
     * @param keyTransformer
     * @param valueTransformer
     * @param <K>
     * @param <V>
     * @param <E>
     */
    public static <K, V, E> void populateMap(final Map<K, V> map, final Iterable<? extends E> elements, final Transformer<E, K> keyTransformer, final Transformer<E, V> valueTransformer) {
        org.apache.commons.collections4.MapUtils.populateMap(map, elements, keyTransformer, valueTransformer);
    }
    
    /**
     * 将普通的{@link java.util.Map}实例转化成{@link org.apache.commons.collections4.IterableMap}实例
     *
     * @param map 输入的{@code Map}实例
     * @param <K> Key类型
     * @param <V> Value类型
     * @return 转换后的{@code IterableMap}实例
     * @throws NullPointerException 如果参数<code>map</code>为<code>null</code>
     */
    public static <K, V> IterableMap<K, V> iterableMap(final Map<K, V> map) {
        return org.apache.commons.collections4.MapUtils.iterableMap(map);
    }
    
    public static <K, V> IterableSortedMap<K, V> iterableSortedMap(final SortedMap<K, V> sortedMap) {
        return org.apache.commons.collections4.MapUtils.iterableSortedMap(sortedMap);
    }
    
    public static int size(final Map<?, ?> map) {
        return org.apache.commons.collections4.MapUtils.size(map);
    }
    
}
